//
// Created by yuhaibo on 18-11-16.
//

#define LOG_TAG "Ota_HAL"
#define LOG_NDEBUG 0
#include "Ota.h"
#include <log/log.h>
#include <future>
#include <cinttypes>
#include <cstring>
#include "asn/src/ErrorCodes.h"
#include "asn/src/SharedElements.h"
#include "asn/src/ConnectivitySts.h"
#include "asn/src/OTANotificationToMaster.h"
#include "asn/src/OTADHUAssignmentNotification.h"
#include "asn/src/OTAWriteInstallationInstruction.h"
#include "asn/src/OTASetAssignmentFileInfo.h"
#include "asn/src/OTASignatureCertificate.h"
#include "asn/src/OTAURLInfo.h"
#include "asn/src/SetScheduleTime.h"
#include "asn/src/NewUserAppSettings.h"
#include "asn/src/OTADownloadStatus.h"
#include "asn/src/SyncSchInstallTime.h"
#include "asn/src/OTAPreSaleInfo.h"

namespace vendor {
namespace ecarx {
namespace xma {
namespace ota {
namespace V2_0 {
const struct { milliseconds common = 50ms; } gDefaultDelay;

using ::android::hardware::hidl_string;
using ::android::hardware::Return;
using ::android::hardware::Void;

// const unsigned int DTC_FLAG_STATE = 1;
// const int32_t DTC_CODE = 0xD08100;

int testMode = 0;

int mWriteInstallationInstructionHandleId = 0;
int mFileInfoHandleId = 0;
int mUrlInfoHandledId = 0;
int mAssignmentkeyHandleId = 0;
int mSignatureCertificateHandleId = 0;

std::optional<bool> mIPCPResponseResult;
std::optional<bool> mStartDownloadResult;
int mRetryCount;
std::chrono::steady_clock::time_point mStartTime;

std::mutex mMutex;
std::condition_variable mCv;
int32_t mDeltaTime;
int32_t mPreSaleStatus;

static char buf[1500] = {
    0,
};

static ipcp_peer_t peer_ota_server = {
    .sk_type = IPCP_TRANSPORT_UDP,
    .peer_ip = PEER_IP,
    .peer_port = PEER_PORT,
};

static ipcp_peer_t peer_ota_vgm_server = {
    .sk_type = IPCP_TRANSPORT_UDP,
    .peer_ip = PEER_VGM_IP,
    .peer_port = PEER_VGM_PORT,
};

static ipcp_peer_t peer_ota_server_test = {
    .sk_type = IPCP_TRANSPORT_UDP,
    .peer_ip = TEST_LOCAL_IP,
    .peer_port = TEST_LOCAL_PORT,
};

static ipcp_peer_t peer_adcu_server = {
    .sk_type = IPCP_TRANSPORT_UDP,
    .peer_ip = PEER_ADCU_IP,
    .peer_port = PEER_ADCU_PORT,
};

static ipcp_peer_t peer_flc_server = {
    .sk_type = IPCP_TRANSPORT_UDP,
    .peer_ip = PEER_FLC_IP,
    .peer_port = PEER_FLC_PORT,
};

uint16_t Connectivity_OperationIDs[12] = {
        OP_ID_OTA_NOTIFICATION_TO_MASTER_CHANGE,
        OP_ID_CONNECTIVITY_STATUS,
        OP_ID_OTA_DHU_ASSIGNMENT_NOTIFICATION,
        OP_ID_OTA_WRITE_INSTALLATION_INSTRUCTION,
        OP_ID_OTA_SET_ASSIGNMENT_FILE_INFO,
        OP_ID_OTA_SIGNATURE_CERTIFICATE,
        OP_ID_OTA_URL_INFO,
        OP_ID_OTA_SET_SCHEDULE_TIME,
        OP_ID_NEW_USER_APP_SETTINGS,
		OP_ID_OTA_DOWNLOAD_STATUS,
        OP_ID_SYNC_SCH_INSTALL_TIME,
        OP_ID_PRE_SALE_INFO,
};

void* cookie;

void ota_received_cb(ipcp_packet_t* packet, ipcp_peer_t peer);
void ota_error_cb(ipcp_packet_t* ipcp_packet, ipcp_stack_err_t error);
void init_ota_side(ipcp_transport_conf_t* config);
void init_ota_side_test(ipcp_transport_conf_t* config);
void init_ota_ipcp_internal();

void init_ota_side(ipcp_transport_conf_t* config) {
    config->service_id = SERVICE_ID;
    strcpy(config->host_ip, LOCAL_IP);
    config->host_port = LOCAL_PORT;
    config->sk_type = IPCP_TRANSPORT_UDP;
    config->vlan = VLAN;
    config->priority = PRIORITY;

    testMode = 0;
}

void init_ota_side_test(ipcp_transport_conf_t* config) {
    config->service_id = SERVICE_ID;
    strcpy(config->host_ip, TEST_LOCAL_IP);
    config->host_port = TEST_LOCAL_PORT;
    config->sk_type = IPCP_TRANSPORT_UDP;
    config->vlan = VLAN;
    config->priority = PRIORITY;

    testMode = 1;
}


void ota_error_cb(ipcp_packet_t* ipcp_packet, ipcp_stack_err_t error) {
    ALOGD("%s, ota recv error cb...", __func__);
    // sp<Ota> ota = Ota::getOta(cookie);
    switch (error) {
        case STACK_FAILURE_CREATE_SOCKET:
        case STACK_FAILURE_SET_VLAN:
        case STACK_FAILURE_BIND_SOCKET:
        case STACK_FAILURE_LISTEN_SOCKET:
        case STACK_FAILURE_ACCEPT_SOCKET:
        case STACK_FAILURE_CONNECT_SOCKET:
        case STACK_FAILURE_CREATE_THREAD:
            ipcp_cleanup();
            sleep(2);
            init_ota_ipcp_internal();
            break;
        case STACK_FAILURE_WFA_TIMEOUT:
            ALOGE("STACK_FAILURE_WFA_TIMEOUT");
            break;
        case STACK_FAILURE_WFR_TIMEOUT:
            ALOGE("STACK_FAILURE_WFR_TIMEOUT");
            break;
        /* case DIAG_ERROR_Code_Invalid_Protocl_Version:
        case DIAG_ERROR_CODE_SERVICE_ID_NOT_AVAILABLE:
        case DIAG_ERROR_Code_OperationID_Not_Available:
        case DIAG_ERROR_Code_OperationType_Not_Available:
        case DIAG_ERROR_Code_Invalid_Length: {
            ALOGE("Invalid IPCP patcket, report DTC");
            ota->reportDtc();
            break;
        } */
        default:
            ALOGE("ota_error_cb default case");
            break;
    }
}

void handleConnectivityStatus(ipcp_packet_t* packet) {
    if (packet == nullptr) return;

    ipcp_header_t* header = &packet->header;
    uint16_t len = header->length - ASN_HEADER_LENGTH_OFFSET;
    ALOGD("OP_ID_CONNECTIVITY_STATUS  operation_id = %x", packet->header.op_type);
    switch (packet->header.op_type) {
        case OP_TYPE_REQUEST: {
            //ALOGE("OP_ID_CONNECTIVITY_STATUS OP_TYPE_REQUEST decode.");
            break;
        }
        case OP_TYPE_RESPONSE:
        case OP_TYPE_NOTIFICATION: {
            //ALOGE("OP_ID_CONNECTIVITY_STATUS OP_TYPE_NOTIFICATION decode.");
            ASN1PERDecodeBuffer decodeBuffer((OSOCTET*)packet->payload, len, false);
            decodeBuffer.setTrace(true);
            decodeBuffer.setDiag(true);
            ASN1T_New_OpConnectivityStatus_Response data;
            ASN1C_New_OpConnectivityStatus_Response OpConnectivityStatus_ResponsePDU(decodeBuffer, data);
            int stat = OpConnectivityStatus_ResponsePDU.Decode();
            if (stat != 0) {
                ALOGE("OP_ID_CONNECTIVITY_STATUS OP_TYPE_NOTIFICATION decode error stat = %d ",
                      stat);
            } else {
                ALOGD("OP_ID_CONNECTIVITY_STATUS OP_TYPE_NOTIFICATION decode success");
                //通知上层ota service
                sp<Ota> ota = Ota::getOta(cookie);
                sp<IOtaClientCallback> callback = ota->getCallback();

                if (callback != NULL) {
                    ALOGD("OP_ID_CONNECTIVITY_STATUS OP_TYPE_NOTIFICATION decode status is = %d ",
                          data.connectionStatus);
                    ConnectivityStsHal conStatus;
                    conStatus.connectionStatus = data.connectionStatus;
                    callback->onConnectivityStsNotification(conStatus);
                }
            }
            break;
        }
        case OP_TYPE_ERROR: {
            ASN1PERDecodeBuffer decodeBuffer((OSOCTET*)packet->payload, len, true);
            ASN1T_OpGeneric_Error data;
            ASN1C_OpGeneric_Error OpGeneric_ErrorPUD(decodeBuffer, data);

            if (OpGeneric_ErrorPUD.Decode()) {
                ALOGE("OP_ID_CONNECTIVITY_STATUS OP_TYPE_ERROR decode error");
            } else {
                //ALOGV("OP_ID_CONNECTIVITY_STATUS OP_TYPE_ERROR decode success");
            }
            break;
        }
        default:
            //ALOGE("Incorret OP_TYPE.");
            break;
    }
}

void handleOTASettingChg(ipcp_packet_t* packet) {
    if (packet == nullptr) return;

    ipcp_header_t* header = &packet->header;
    uint16_t len = header->length - ASN_HEADER_LENGTH_OFFSET;
    ALOGD("OP_ID_NEW_USER_APP_SETTINGS  operation_id = %x", packet->header.op_type);
    switch (packet->header.op_type) {
        case OP_TYPE_REQUEST: {
            //ALOGE("OP_ID_NEW_USER_APP_SETTINGS OP_TYPE_REQUEST decode.");
            break;
        }
        case OP_TYPE_RESPONSE:
            break;
        case OP_TYPE_NOTIFICATION: {
            //ALOGE("OP_ID_NEW_USER_APP_SETTINGS OP_TYPE_NOTIFICATION decode.");
            ASN1PERDecodeBuffer decodeBuffer((OSOCTET*)packet->payload, len, false);
            decodeBuffer.setTrace(true);
            decodeBuffer.setDiag(true);
            ASN1T_New_OpUserAppSettings_Notification data;
            ASN1C_New_OpUserAppSettings_Notification OpUserAppSettings_NotificationPDU(decodeBuffer, data);
            int stat = OpUserAppSettings_NotificationPDU.Decode();
            if (stat != 0) {
                ALOGE("OP_ID_NEW_USER_APP_SETTINGS OP_TYPE_NOTIFICATION decode error stat = %d ",
                      stat);
            } else {
                ALOGD("OP_ID_NEW_USER_APP_SETTINGS OP_TYPE_NOTIFICATION decode success");
                //通知上层ota service
                sp<Ota> ota = Ota::getOta(cookie);
                sp<IOtaClientCallback> callback = ota->getCallback();

                if (callback != NULL) {
                    OpOTAUserOtaSettingsHal otaSettings;
                    if (data.userOTASetting.m.otasettingPresent) {
                        otaSettings.otasetting = data.userOTASetting.otasetting;
                    } else {
                        otaSettings.otasetting = 0XFF;
                    }
                    if (data.userOTASetting.m.autosyncPresent) {
                        otaSettings.autosync = data.userOTASetting.autosync;
                    } else {
                        otaSettings.autosync = 0XFF;
                    }
                    if (data.userOTASetting.m.autodownloadPresent) {
                        otaSettings.autodownload = data.userOTASetting.autodownload;
                    } else {
                        otaSettings.autodownload = 0XFF;
                    }
                    if (data.userOTASetting.m.autoinstallationPresent) {
                        otaSettings.autoinstallation = data.userOTASetting.autoinstallation;
                    } else {
                        otaSettings.autoinstallation = 0XFF;
                    }
                    if (data.userOTASetting.m.nightinstallationPresent) {
                        otaSettings.nightinstallation = data.userOTASetting.nightinstallation;
                        ALOGD("handleOTASettingChg night is = %d ", otaSettings.nightinstallation);
                    } else {
                        otaSettings.nightinstallation = 0XFF;
                    }
                    if (data.userOTASetting.m.pre_salePresent) {
                        otaSettings.pre_sale = data.userOTASetting.pre_sale;
                    } else {
                        otaSettings.pre_sale = 0XFF;
                    }
                    if (data.userOTASetting.m.gdprPresent) {
                        otaSettings.gdpr = data.userOTASetting.gdpr;
                    } else {
                        otaSettings.gdpr = 0XFF;
                    }
                    callback->onOTASettingChg(otaSettings);
                }
            }
            break;
        }
        case OP_TYPE_ERROR: {
            ASN1PERDecodeBuffer decodeBuffer((OSOCTET*)packet->payload, len, true);
            ASN1T_OpGeneric_Error data;
            ASN1C_OpGeneric_Error OpGeneric_ErrorPUD(decodeBuffer, data);

            if (OpGeneric_ErrorPUD.Decode()) {
                ALOGE("OP_ID_NEW_USER_APP_SETTINGS OP_TYPE_ERROR decode error");
            } else {
                //ALOGV("OP_ID_NEW_USER_APP_SETTINGS OP_TYPE_ERROR decode success");
            }
            break;
        }
        default:
            //ALOGE("Incorret OP_TYPE.");
            break;
    }
}

void handleNotificationToMasterChange(ipcp_packet_t* packet) {
    if (packet == nullptr){
        return;
    }

    ipcp_header_t* header = &packet->header;
    uint16_t len = header->length - ASN_HEADER_LENGTH_OFFSET;
    ALOGD("OP_ID_OTA_NOTIFICATION_TO_MASTER_CHANGE  operation_id = %x", packet->header.op_type);
    switch (packet->header.op_type) {
        case OP_TYPE_REQUEST: {
            //ALOGE("OP_ID_CONNECTIVITY_STATUS OP_TYPE_REQUEST decode.");
            ASN1PERDecodeBuffer decodeBuffer((OSOCTET*)packet->payload, len, false);
            decodeBuffer.setTrace(true);
            decodeBuffer.setDiag(true);
            ASN1T_OpOTANotificationToMaster_Request data;
            ASN1C_OpOTANotificationToMaster_Request OpOTANotificationToMaster_RequestPDU(decodeBuffer, data);
            int stat = OpOTANotificationToMaster_RequestPDU.Decode();
            if (stat !=0 ) {
                ALOGE("handleNotificationToMasterChange OP_TYPE_REQUEST decode error stat = %d ",
                      stat);
            } else {
                ALOGD("handleNotificationToMasterChange OP_TYPE_REQUEST decode success");
                //通知上层ota service
                sp<Ota> ota = Ota::getOta(cookie);
                sp<IOtaClientCallback> callback = ota->getCallback();
                if (callback != NULL) {
                    ALOGD("handleNotificationToMasterChange OP_TYPE_REQUEST decode installationorder is = %s ",
                          data.installationorder.uuid);
                    ALOGD("handleNotificationToMasterChange OP_TYPE_REQUEST decode isotimestamp is = %s ",
                          data.isotimestamp.timestamp);
                    ALOGD("handleNotificationToMasterChange OP_TYPE_REQUEST decode newstatus is = %s ",
                          data.newstatus);
                    ALOGD("handleNotificationToMasterChange OP_TYPE_REQUEST decode reason is = %s ",
                          data.reason);
                    ALOGD("handleNotificationToMasterChange OP_TYPE_REQUEST decode deltatime is = %d ",
                          data.deltatime);
                    OpOTATCAMAssignmentParamHal paramHal;
                    paramHal.installationorder = data.installationorder.uuid;
                    paramHal.isotimestamp = data.isotimestamp.timestamp;
                    paramHal.newstatus = data.newstatus;
                    paramHal.reason = data.reason;
                    paramHal.deltatime = data.deltatime;
                    callback->onNotificationToMasterChange(paramHal);
                }
            }
            break;
        }
        case OP_TYPE_RESPONSE:
        case OP_TYPE_NOTIFICATION: {
            ALOGE("OP_ID_OTA_NOTIFICATION_TO_MASTER_CHANGE OP_TYPE_NOTIFICATION decode.");
            break;
        }
        case OP_TYPE_ERROR: {
            ASN1PERDecodeBuffer decodeBuffer((OSOCTET*)packet->payload, len, true);
            ASN1T_OpGeneric_Error data;
            ASN1C_OpGeneric_Error OpGeneric_ErrorPUD(decodeBuffer, data);

            if (OpGeneric_ErrorPUD.Decode()) {
                ALOGE("OP_ID_CONNECTIVITY_STATUS OP_TYPE_ERROR decode error");
            } else {
                //ALOGV("OP_ID_CONNECTIVITY_STATUS OP_TYPE_ERROR decode success");
            }
            break;
        }
        default:
            //ALOGE("Incorret OP_TYPE.");
            break;
    }
}

void handleWriteInstallInstructionResponse(ipcp_packet_t* packet) {
    if (packet == nullptr) return;

    ipcp_header_t* header = &packet->header;
    uint16_t len = header->length - ASN_HEADER_LENGTH_OFFSET;
    ALOGD("OP_ID_OTA_WRITE_INSTALLATION_INSTRUCTION  operation_id = %x", packet->header.op_type);
    switch (packet->header.op_type) {
        case OP_TYPE_REQUEST: {
            break;
        }
        case OP_TYPE_RESPONSE: {
            ASN1PERDecodeBuffer decodeBuffer((OSOCTET*)packet->payload, len, false);
            decodeBuffer.setTrace(true);
            decodeBuffer.setDiag(true);
            ASN1T_New_OpOTAWriteInstallationInstructions_Response data;
            ASN1C_New_OpOTAWriteInstallationInstructions_Response OpOTAWriteInstallationInstructions_ResponsePDU(decodeBuffer, data);
            int stat = OpOTAWriteInstallationInstructions_ResponsePDU.Decode();
            
            if (stat != 0) {
                ALOGE("OP_ID_OTA_WRITE_INSTALLATION_INSTRUCTION OP_TYPE_RESPONSE decode error stat = %d ",
                      stat);
            } else {
                ALOGD("OP_ID_OTA_WRITE_INSTALLATION_INSTRUCTION OP_TYPE_RESPONSE decode success");
                ALOGD("decode status is %s", data.status);
                if (strcmp(data.status, "OK") == 0) {
                    mIPCPResponseResult = true;
                } else {
                    mIPCPResponseResult = false;
                }
            }
            break;
        }
        case OP_TYPE_NOTIFICATION: {
            break;
        }
        default:
            break;
    }
}

void handleAssignmentFileInfoResponse(ipcp_packet_t* packet) {
    if (packet == nullptr) return;

    ipcp_header_t* header = &packet->header;
    uint16_t len = header->length - ASN_HEADER_LENGTH_OFFSET;
    ALOGD("OP_ID_OTA_SET_ASSIGNMENT_FILE_INFO  operation_id = %x", packet->header.op_type);
    switch (packet->header.op_type) {
        case OP_TYPE_REQUEST: {
            break;
        }
        case OP_TYPE_RESPONSE: {
            ASN1PERDecodeBuffer decodeBuffer((OSOCTET*)packet->payload, len, false);
            decodeBuffer.setTrace(true);
            decodeBuffer.setDiag(true);
            ASN1T_New_OpOTASetAssignmentFileInfo_Response data;
            ASN1C_New_OpOTASetAssignmentFileInfo_Response opOTASetAssignmentFileInfo__ResponsePDU(decodeBuffer, data);
            int stat = opOTASetAssignmentFileInfo__ResponsePDU.Decode();
            
            if (stat != 0) {
                ALOGE("OP_ID_OTA_SET_ASSIGNMENT_FILE_INFO OP_TYPE_RESPONSE decode error stat = %d ",
                      stat);
            } else {
                ALOGD("OP_ID_OTA_SET_ASSIGNMENT_FILE_INFO OP_TYPE_RESPONSE decode success");
                ALOGD("decode status is %s", data.status);
                if (strcmp(data.status, "OK") == 0) {
                    mIPCPResponseResult = true;
                } else {
                    mIPCPResponseResult = false;
                }
            }
            break;
        }
        case OP_TYPE_NOTIFICATION: {
            break;
        }
        default:
            break;
    }
}

void handleSignatureCertificateResponse(ipcp_packet_t* packet) {
    if (packet == nullptr) return;

    ipcp_header_t* header = &packet->header;
    uint16_t len = header->length - ASN_HEADER_LENGTH_OFFSET;
    ALOGD("OP_ID_OTA_SIGNATURE_CERTIFICATE  operation_id = %x", packet->header.op_type);
    switch (packet->header.op_type) {
        case OP_TYPE_REQUEST: {
            break;
        }
        case OP_TYPE_RESPONSE: {
            ASN1PERDecodeBuffer decodeBuffer((OSOCTET*)packet->payload, len, false);
            decodeBuffer.setTrace(true);
            decodeBuffer.setDiag(true);
            ASN1T_New_OpOTASignatureCertificate_Response data;
            ASN1C_New_OpOTASignatureCertificate_Response opOTASignatureCertificate__ResponsePDU(decodeBuffer, data);
            int stat = opOTASignatureCertificate__ResponsePDU.Decode();
            
            if (stat != 0) {
                ALOGE("OP_ID_OTA_SIGNATURE_CERTIFICATE OP_TYPE_RESPONSE decode error stat = %d ",
                      stat);
            } else {
                ALOGD("OP_ID_OTA_SIGNATURE_CERTIFICATE OP_TYPE_RESPONSE decode success");
                ALOGD("decode status is %s", data.oTASignatureCertificateResp);
                // if (strcmp(data.oTASignatureCertificateResp, "OK") == 0) {
                //     mIPCPResponseResult = true;
                // } else {
                //     mIPCPResponseResult = false;
                // }
                //zeekr方案上暂时忽略oTASignatureCertificateResp的返回，直接认为成功
                mIPCPResponseResult = true;
            }
            break;
        }
        case OP_TYPE_NOTIFICATION: {
            break;
        }
        default:
            break;
    }
}

void handleAssignmentFileUrlResponse(ipcp_packet_t* packet) {
    if (packet == nullptr) return;

    ipcp_header_t* header = &packet->header;
    uint16_t len = header->length - ASN_HEADER_LENGTH_OFFSET;
    ALOGD("OP_ID_OTA_URL_INFO  operation_id = %x", packet->header.op_type);
    switch (packet->header.op_type) {
        case OP_TYPE_REQUEST: {
            break;
        }
        case OP_TYPE_RESPONSE: {
            ASN1PERDecodeBuffer decodeBuffer((OSOCTET*)packet->payload, len, false);
            decodeBuffer.setTrace(true);
            decodeBuffer.setDiag(true);
            ASN1T_New_OpOTAURLInfo_Response data;
            ASN1C_New_OpOTAURLInfo_Response opOTAURLInfo_ResponsePDU(decodeBuffer, data);
            int stat = opOTAURLInfo_ResponsePDU.Decode();
                       
            if (stat != 0) {
                ALOGE("OP_ID_OTA_URL_INFO OP_TYPE_RESPONSE decode error stat = %d ",
                      stat);
            } else {
                ALOGD("OP_ID_OTA_URL_INFO OP_TYPE_RESPONSE decode success");
                ALOGD("decode status is %s", data.status);
                if (strcmp(data.status, "OK") == 0) {
                    mIPCPResponseResult = true;
                } else {
                    mIPCPResponseResult = false;
                }
            }
            break;
        }
        case OP_TYPE_NOTIFICATION: {
            break;
        }
        default:
            break;
    }
}

void handleECUDownloadStatusNotification(ipcp_packet_t* packet, ipcp_peer_t peer) {
    if (packet == nullptr) return;

    ipcp_header_t* header = &packet->header;
    uint16_t len = header->length - ASN_HEADER_LENGTH_OFFSET;
    ALOGD("OP_ID_OTA_URL_INFO  operation_id = %x", packet->header.op_type);
    switch (packet->header.op_type) {
        case OP_TYPE_REQUEST: {
            break;
        }
        case OP_TYPE_RESPONSE: {
            break;
        }
        case OP_TYPE_NOTIFICATION: {
            ASN1PERDecodeBuffer decodeBuffer((OSOCTET*)packet->payload, len, false);
            decodeBuffer.setTrace(true);
            decodeBuffer.setDiag(true);
            ASN1T_New_OpOTADownloadStatus_Notification data;
            ASN1C_New_OpOTADownloadStatus_Notification OpOTADownloadStatus_NotificationPDU(decodeBuffer, data);
            int stat = OpOTADownloadStatus_NotificationPDU.Decode();
                       
            if (stat != 0) {
                ALOGE("OP_ID_OTA_DOWNLOAD_STATUS OP_TYPE_NOTIFICATION decode error stat = %d ", stat);
            } else {
                ALOGD("OP_ID_OTA_DOWNLOAD_STATUS OP_TYPE_NOTIFICATION decode success");
                //通知上层ota service
                sp<Ota> ota = Ota::getOta(cookie);
                sp<IOtaClientCallback> callback = ota->getCallback();
                if (callback != NULL) {
                    ALOGD("handleECUDownloadStatusNotification decode installationorder is = %s ", data.installationorder.uuid);
                    ALOGD("handleECUDownloadStatusNotification decode isotimestamp is = %s ", data.isotimestamp.timestamp);
                    ALOGD("handleECUDownloadStatusNotification decode newstatus is = %s ", data.newstatus);
                    ALOGD("handleECUDownloadStatusNotification decode reason is = %s ", data.reason);
                    ALOGD("handleECUDownloadStatusNotification decode downloadsize is = %d ", data.downloadsize);
                    OpOTADownloadStatusHal paramHal;
                    paramHal.installationorder = data.installationorder.uuid;
                    paramHal.isotimestamp = data.isotimestamp.timestamp;
                    paramHal.newstatus = data.newstatus;
                    paramHal.reason = data.reason;
                    paramHal.downloadsize = data.downloadsize;

                    if (strcmp(peer.peer_ip, PEER_ADCU_IP) == 0) {
                        paramHal.ecuaddress = DIAGNOSE_ADDR_ADCU;
                    } else if (strcmp(peer.peer_ip, PEER_FLC_IP) == 0) {
                        paramHal.ecuaddress = DIAGNOSE_ADDR_FLC;
                    } else {
                        ALOGE("handleECUDownloadStatusNotification decode peer ip is error");
                    }

                    callback->onECUDownloadStsNotification(paramHal);
                }
            }
            break;
        }
        default:
            break;
    }
}

void handleSyncSchInstallTime(ipcp_packet_t* packet) {
    if (packet == nullptr) return;

    ipcp_header_t* header = &packet->header;
    uint16_t len = header->length - ASN_HEADER_LENGTH_OFFSET;
    ALOGD("OP_ID_SYNC_SCH_INSTALL_TIME  operation_id = %x", packet->header.op_type);
    switch (packet->header.op_type) {
        case OP_TYPE_REQUEST: {
            //ALOGE("OP_ID_SYNC_SCH_INSTALL_TIME OP_TYPE_REQUEST decode.");
            break;
        }
        case OP_TYPE_NOTIFICATION: {
            //ALOGE("OP_ID_SYNC_SCH_INSTALL_TIME OP_TYPE_NOTIFICATION decode.");
            break;
        }
        case OP_TYPE_RESPONSE: {
            //ALOGE("OP_ID_SYNC_SCH_INSTALL_TIME OP_TYPE_RESPONSE decode.");
            ASN1PERDecodeBuffer decodeBuffer((OSOCTET*)packet->payload, len, false);
            decodeBuffer.setTrace(true);
            decodeBuffer.setDiag(true);
            ASN1T_New_OpSyncSchInstallTime_Response data;
            ASN1C_New_OpSyncSchInstallTime_Response OpSyncSchInstallTime_ResponsePDU(decodeBuffer, data);
            int stat = OpSyncSchInstallTime_ResponsePDU.Decode();
            if (stat != 0) {
                ALOGE("OP_ID_SYNC_SCH_INSTALL_TIME OP_TYPE_RESPONSE decode error stat = %d ", stat);
            } else {
                // 通知收到时间，让请求往下执行返回
                std::lock_guard<std::mutex> lock(mMutex);
                mDeltaTime = data.schInstalldeltatime;
                mCv.notify_all();
                ALOGD("receive delta time:%d", mDeltaTime);
            }
            break;
        }
        case OP_TYPE_ERROR: {
            ASN1PERDecodeBuffer decodeBuffer((OSOCTET*)packet->payload, len, true);
            ASN1T_OpGeneric_Error data;
            ASN1C_OpGeneric_Error OpGeneric_ErrorPUD(decodeBuffer, data);

            if (OpGeneric_ErrorPUD.Decode()) {
                ALOGE("OP_ID_SYNC_SCH_INSTALL_TIME OP_TYPE_ERROR decode error");
            } else {
                //ALOGV("OP_ID_SYNC_SCH_INSTALL_TIME OP_TYPE_ERROR decode success");
            }
            break;
        }
        default:
            //ALOGE("Incorret OP_TYPE.");
            break;
    }
}

void handlePreSaleInfo(ipcp_packet_t* packet) {
    if (packet == nullptr) return;

    ipcp_header_t* header = &packet->header;
    uint16_t len = header->length - ASN_HEADER_LENGTH_OFFSET;
    ALOGD("OP_ID_PRE_SALE_INFO  operation_id = %x", packet->header.op_type);
    switch (packet->header.op_type) {
        case OP_TYPE_REQUEST: {
            break;
        }
        case OP_TYPE_NOTIFICATION: {
            break;
        }
        case OP_TYPE_RESPONSE: {
            ASN1PERDecodeBuffer decodeBuffer((OSOCTET*)packet->payload, len, false);
            decodeBuffer.setTrace(true);
            decodeBuffer.setDiag(true);
            ASN1T_OpOTAPreSaleInfo_Response data;
            ASN1C_OpOTAPreSaleInfo_Response OpOTAPreSaleInfo_Response(decodeBuffer, data);
            int stat = OpOTAPreSaleInfo_Response.Decode();
            std::lock_guard<std::mutex> lock(mMutex);
            if (stat != 0) {
                mPreSaleStatus = (int32_t) StatusCode::FAILED;
                ALOGE("OP_ID_PRE_SALE_INFO OP_TYPE_RESPONSE decode error stat = %d ", stat);
            } else {
                ALOGD("receive pre sale response:%s", data.status1);
                if (strcmp(data.status1, "OK") == 0) {
                    mPreSaleStatus = (int32_t) StatusCode::SUCCESS;
                } else {
                    mPreSaleStatus = (int32_t) StatusCode::FAILED;
                }
            }
            // 通知setTcamSalesMode往下执行
            mCv.notify_all();
            break;
        }
        case OP_TYPE_ERROR: {
            ASN1PERDecodeBuffer decodeBuffer((OSOCTET*)packet->payload, len, true);
            ASN1T_OpGeneric_Error data;
            ASN1C_OpGeneric_Error OpGeneric_ErrorPUD(decodeBuffer, data);

            if (OpGeneric_ErrorPUD.Decode()) {
                ALOGE("OP_ID_PRE_SALE_INFO OP_TYPE_ERROR decode error");
            } else {
                ALOGV("OP_ID_PRE_SALE_INFO OP_TYPE_ERROR decode success");
            }
            break;
        }
        default:
            //ALOGE("Incorret OP_TYPE.");
            break;
    }
}

/*char to hex*/
int char2hex(char ch) {
    int result = 0;
    if(ch >= 'a' && ch <= 'f') {
        result = ch - 'a' + 10;
    } else if(ch >= 'A' && ch <= 'F') {
        result = ch - 'A' + 10;
    } else if(ch >= '0' && ch <= '9') {
        result = ch - '0';
    } else {
        ALOGE("%s, invalid ch = %c", __func__, result);
    }
    return result;
}


void string2OCTET(char* str, OSOCTET* octet) {
    int len = strlen(str);
    ALOGD("%s, len = %d, str = %s", __func__, len, str);
    //将str中的str[0]和str[1]转换为16进制数，存放在octet[0]中

    for (int i = 0; i < len / 2; i++) {
        //ALOGD("%s, str[%d] = %c, str[%d] = %c", __func__, i*2, str[i*2], i*2+1, str[i*2+1]);
        OSOCTET highNibble = static_cast<OSOCTET>(char2hex(str[i*2]));
        OSOCTET lowNibble = static_cast<OSOCTET>(char2hex(str[i*2+1]));
        //ALOGD("%s, highNibble = %u, lowNibble = %u, highNibbl-hhu = %hhu, lowNibble-hhu = %hhu", __func__, highNibble, lowNibble, highNibble, lowNibble);
        octet[i] = (highNibble << 4) | (lowNibble & 0x0F);
        //ALOGD("%s, octet[%d] = %u, octet-huu = %hhu", __func__, i, octet[i], octet[i]);
    }
    //ALOGD("%s, octet = %s", __func__, octet);
}


void ota_received_cb(ipcp_packet_t* packet, ipcp_peer_t peer) {
    ipcp_header_t* header = &packet->header;
    uint16_t len = header->length - ASN_HEADER_LENGTH_OFFSET;
    //ALOGV("<-------------------------------------------------------------------->");
    ALOGV("<--------------ota hal receive package info--------------------->");
    ALOGV("%s, received ipcp header : sid: %#x, op_id: %#x, op_type: %#x", __func__,
          header->service_id, header->operation_id, header->op_type);
    //ALOGV("<-------------------------------------------------------------------->");
    std::string otasettingProperty = android::base::GetProperty(OTA_SETTING, "");
    std::string autosyncProperty = android::base::GetProperty(OTA_AUTO_SYNC, "");
    ALOGD("%s, otasettingProperty is %s", __func__, otasettingProperty.c_str());
    ALOGD("%s, autosyncProperty is %s", __func__, autosyncProperty.c_str());
    if ("0" == otasettingProperty) {
        return;
    }
    if (header->service_id != SERVICE_ID_OTA) {
        ALOGE("%s, invalid service id %hu detected !!!\n", __func__, header->service_id);
        return;
    }
    switch (header->operation_id) {
        case OP_ID_CONNECTIVITY_STATUS:
            handleConnectivityStatus(packet);
            break;
        case OP_ID_OTA_NOTIFICATION_TO_MASTER_CHANGE:
            handleNotificationToMasterChange(packet);
            break;
        case OP_ID_OTA_WRITE_INSTALLATION_INSTRUCTION:
            handleWriteInstallInstructionResponse(packet);
            break;
        case OP_ID_OTA_URL_INFO:
            handleAssignmentFileUrlResponse(packet);
            break;
        case OP_ID_OTA_SIGNATURE_CERTIFICATE:
            handleSignatureCertificateResponse(packet);
            break;
        case OP_ID_OTA_SET_ASSIGNMENT_FILE_INFO:
            handleAssignmentFileInfoResponse(packet);
            break;
        case OP_ID_NEW_USER_APP_SETTINGS:
            handleOTASettingChg(packet);
            break;
		case OP_ID_OTA_DOWNLOAD_STATUS:
            handleECUDownloadStatusNotification(packet, peer);
            break;
        case OP_ID_SYNC_SCH_INSTALL_TIME:
            handleSyncSchInstallTime(packet);
            break;
        case OP_ID_PRE_SALE_INFO:
            handlePreSaleInfo(packet);
            break;
        default:
            ALOGE("%s, unknown operation ID: %hu", __func__, header->operation_id);
            return;
    }

    //ALOGV("%s, received ipcp header : sid: %hu\n", __func__, header->service_id);
    for (uint16_t i = 0; i < len; i++) {
        //ALOGE("%s, %#x", __func__, packet->payload[i]);
    }
}


ipcp_callbacks_t ota_callbacks = {
    .ipcp_received_cb = ota_received_cb,
    .error_cb = ota_error_cb,
};

Ota::Ota() : mCallbackDeathRecipient(new DeathRecipient(this)) {
    //ALOGD("%s", __func__);
    cookie = this;
}

Ota::~Ota() {
    //ALOGD("%s", __func__);
    ipcp_cleanup();
}

sp<Ota> Ota::getOta(void* cookie) {
    //ALOGI("%s", __func__);
    wp<Ota> weak(reinterpret_cast<Ota*>(cookie));
    sp<Ota> ota = weak.promote();
    return ota;
}

void Ota::onFirstRef() {
    //ALOGD("%s", __func__);
}

Return<StatusCode> Ota::init_ota_ipcp() {
    ALOGD("%s", __func__);

    ipcp_transport_conf_t client_config;
    ipcp_stack_err_t error_code;

    init_ota_side(&client_config);
    error_code = ipcp_setup_with_opids(client_config, &ota_callbacks, Connectivity_OperationIDs, (sizeof(Connectivity_OperationIDs) / sizeof(Connectivity_OperationIDs[0])));

    if (error_code != 0) {
        ALOGE("ota client side setup error: %d", error_code);
        return StatusCode::FAILED;
    } else {
        //ALOGV("ota client side setup success");
        // setupDtcnl();
        return StatusCode::SUCCESS;
    }
}

void init_ota_ipcp_internal() {
    ALOGD("%s", __func__);
    // sp<Ota> ota = Ota::getOta(cookie);

    ipcp_transport_conf_t client_config;
    ipcp_stack_err_t error_code;

    init_ota_side(&client_config);
    error_code = ipcp_setup_with_opids(client_config, &ota_callbacks, Connectivity_OperationIDs, (sizeof(Connectivity_OperationIDs) / sizeof(Connectivity_OperationIDs[0])));

    if (error_code != 0) {
        ALOGE("ota client side setup error: %d", error_code);
    } else {
        //ALOGV("ota client side setup success");
    }
    // ota->setupDtcnl();
}



Return<StatusCode> Ota::subscribe(const ::android::sp<IOtaClientCallback>& callback) {
    ALOGI("%s", __func__);
    lock_guard<mutex> lk(mMut);
    StatusCode ret = StatusCode::FAILED;
    auto res = callback->linkToDeath(mCallbackDeathRecipient, 0);
    if (!res.isOk()) {  // Client is already dead?
        ALOGW("%s failed to link to death, client %p, err: %s", __func__, callback.get(),
              res.description().c_str());
    }

    if (mCallback == NULL) {
        mCallback = callback;
        ret = StatusCode::SUCCESS;
    } else {
        ALOGE("subscribe failed! do not unsubscribe!");
    }

    return ret;
}

Return<StatusCode> Ota::unsubscribe(const ::android::sp<IOtaClientCallback>& callback) {
    ALOGI("%s", __func__);
    lock_guard<mutex> lk(mMut);
    StatusCode ret = StatusCode::FAILED;
    auto res = callback->unlinkToDeath(mCallbackDeathRecipient);
    if (!res.isOk()) {
        ALOGW("%s failed to unlink to death, client: %p, err: %s", __func__, callback.get(),
              res.description().c_str());
    }
    if (mCallback != NULL) {
        mCallback = NULL;
        ret = StatusCode::SUCCESS;
    } else {
        ALOGE("already unsubscribe!");
    }
    return ret;
}

sp<IOtaClientCallback> Ota::getCallback() {
    if (mCallback != NULL) {
        return mCallback;
    } else {
        return NULL;
    }
}

Return<StatusCode> Ota::requestOTAConnectivitySts() {
    ALOGI("%s", __func__);

    auto task = []() {
        const char* content = NULL;
        int stat, len;
        bool trace = FALSE;
        ipcp_stack_err_t err;
        ASN1PEREncodeBuffer encodeBuffer(false);
        ASN1C_OpGeneric_Request OpGeneric_RequestPDU(encodeBuffer);
        if ((stat = OpGeneric_RequestPDU.Encode()) == 0) {
            if (trace) {
                ALOGV("Encoding was successful\n");
                encodeBuffer.hexDump();
                encodeBuffer.binDump("Data");
            }
            len = encodeBuffer.getMsgLen();
            content = (char*)encodeBuffer.getMsgPtr();
            ipcp_packet_t *packet = build_ipcp_packet(SERVICE_ID, OP_ID_CONNECTIVITY_STATUS,
                                                      OP_TYPE_REQUEST, IPCP_DATA_ENCODED,(void *)content, len);

            if ((err = ipcp_send(peer_ota_server, packet)) != STACK_SEND_MSG_SUCCESS) {
                ALOGE("%s: ipcp_send err : %d", __FUNCTION__, err);
            } else {
                ALOGV("requestOTAConnectivitySts ipcp send success");
            }

        } else {
            ALOGE("requestOTAConnectivitySts OpGeneric_RequestPDU encode failed\n");
            encodeBuffer.printErrorInfo();
        }
    };
    mThread.schedule(task, gDefaultDelay.common);
    return StatusCode::SUCCESS;
}

void Ota::sendDHUAssignmentNotification(const char* ecuaddress, const char* uuid, const char* timestamp, const char* newstatus, const char* reason) {
    ALOGI("%s", __func__);
    //0x0B24
    auto task = [ecuaddress, uuid, timestamp, newstatus, reason]() {
        const char* content = NULL;
        int stat, len;
        bool trace = FALSE;
        
        ipcp_stack_err_t err = STACK_FAILURE_UNKOWN;
        ASN1PEREncodeBuffer encodeBuffer(false);
        ASN1T_OpOTADHUAssignmentNotification_Notification data;
        data.installationorder.uuid = uuid;
        data.isotimestamp.timestamp = timestamp;
        data.newstatus =  newstatus;
        data.reason = reason;
        data.m.reasonPresent = 1;
        ALOGD("newstatus:%s, reason:%s", data.newstatus, data.reason);

        ASN1C_OpOTADHUAssignmentNotification_Notification OpOTADHUAssignment_Notification(encodeBuffer, data);
        if ((stat = OpOTADHUAssignment_Notification.Encode()) == 0) {
            if (trace) {
                ALOGV("sendDHUAssignmentNotification Encoding was successful\n");
                ALOGV("sendDHUAssignmentNotification Hex dump of encoded record:\n");
                encodeBuffer.hexDump();
                ALOGV("sendDHUAssignmentNotification Binary dump:\n");
                encodeBuffer.binDump("Data");
            }
            ALOGV("OpOTADHUAssignment_Notification encode success");
            len = encodeBuffer.getMsgLen();
            content = (char*)encodeBuffer.getMsgPtr();
            ipcp_packet_t* packet = build_ipcp_packet(SERVICE_ID, OP_ID_OTA_DHU_ASSIGNMENT_NOTIFICATION, OP_TYPE_NOTIFICATION, IPCP_DATA_ENCODED, (void*)content, len);                      
            if (ecuaddress == NULL) {
                ALOGE("sendDHUAssignmentNotification ecuaddress is null\n");
                err = STACK_FAILURE_PARM_INVALID;
            } else if (strcmp(ecuaddress, DIAGNOSE_ADDR_ADCU) == 0) {
                ALOGD("sendDHUAssignmentNotification send ipcp to adcu\n");
                err = ipcp_send(peer_adcu_server, packet); 
            } else if (strcmp(ecuaddress, DIAGNOSE_ADDR_FLC) == 0) {
                ALOGD("sendDHUAssignmentNotification send ipcp to flc\n");
                err = ipcp_send(peer_flc_server, packet); 
            } else {

            }
                                 
            if (err != STACK_SEND_MSG_SUCCESS) {
                ALOGE("%s: ipcp_send err : %d", __FUNCTION__, err);
            } else {
                ALOGV("sendDHUAssignmentNotification ipcp send success");
            }
        } else {
            ALOGE("OpOTADHUAssignment_Notification encode failed\n");
            encodeBuffer.printErrorInfo();
        }
    };
    mThread.schedule(task, gDefaultDelay.common);
}

void Ota::sendUrlInfoRequest() {
    ALOGI("%s", __func__);
    //0B64
    auto task = [this]() {
        const char* content = NULL;
        char* tmpData = NULL;
        char* ecuaddress = (char*)this->mRequest.ecuAddress.c_str();
        char* encryptionType = NULL;
        char* encryptionInfo = NULL;
        int stat, len;
        bool trace = FALSE;
        int32_t fileSize = 0;

        ipcp_stack_err_t err = STACK_FAILURE_UNKOWN;
        ASN1PEREncodeBuffer encodeBuffer(false);
        ASN1T_New_OpOTAURLInfo_Request data;

        data.m.downloadtypePresent = 1;
        data.m.encryptinfoPresent = 1;
        data.m.encryptiontypePresent = 1;
        data.m.fileSizePresent = 1;
        data.m.specifiedurlPresent = 1;

        data.installationorder.uuid = (const char*)mRequest.installationOrderId.c_str();

        string2OCTET(ecuaddress, data.ecuaddress.addr.data);
        data.ecuaddress.addr.numocts = strlen(ecuaddress) / 2;

        // ADCU 那边不关注这个字段
        data.downloadtype.numocts = 1;
        data.downloadtype.data[0] = 0x01;//Download to target ECU

        if(mRequest.softwareInstallationInstructions.size()) {
            encryptionType = (char*)mRequest.softwareInstallationInstructions[0].encryptionType.c_str();
            encryptionInfo = (char*)mRequest.softwareInstallationInstructions[0].encryptionInfo.c_str();
        }
        ALOGD("%s: encryptionType = %s ", __func__, encryptionType);
        ALOGD("%s: encryptionInfo = %s ", __func__, encryptionInfo);

        string2OCTET(encryptionType, data.encryptiontype.data);
        data.encryptiontype.numocts = strlen(encryptionType) / 2;

        string2OCTET(encryptionInfo, data.encryptinfo.data);
        data.encryptinfo.numocts = strlen(encryptionType) / 2;

        ALOGD("%s: data.installationorder.uuid = %s ", __func__, data.installationorder.uuid);

        if (mRequest.softwareInstallationInstructions.size() > 0) {
            ASN1C__SetOfNew_Specifiedurl specifiedurlList(
                        data.specifiedurl);
            
            for (size_t i = 0; i < mRequest.softwareInstallationInstructions.size(); i++) {
                SoftwareInstallationInstructionHal softwareInstallationInstructionHal = this->mRequest.softwareInstallationInstructions[i];
                ASN1T_New_Specifiedurl* specifiedurl = specifiedurlList.AppendNewElement();

                specifiedurl->url = (OSUTF8CHAR*)softwareInstallationInstructionHal.url.c_str();
                fileSize += softwareInstallationInstructionHal.fileSize;

                ALOGD("%s: i = %zu  url = %s ", __func__, i,  specifiedurl->url);
                ALOGD("%s: i = %zu  fileSize = %d ", __func__, i,  fileSize);
            }
        }
        data.fileSize = fileSize;
        
        ASN1C_New_OpOTAURLInfo_Request opOTAURLInfoRequest(encodeBuffer, data);
        if ((stat = opOTAURLInfoRequest.Encode()) == 0) {
            if (trace) {
                ALOGV("sendUrlInfoRequest Encoding was successful\n");
                ALOGV("sendUrlInfoRequest Hex dump of encoded record:\n");
                encodeBuffer.hexDump();
                ALOGV("sendUrlInfoRequest Binary dump:\n");
                encodeBuffer.binDump("Data");
            }
            ALOGV("sendUrlInfoRequest encode success");
            len = encodeBuffer.getMsgLen();
            content = (char*)encodeBuffer.getMsgPtr();
            ipcp_packet_t* packet = build_ipcp_packet(SERVICE_ID, OP_ID_OTA_URL_INFO, OP_TYPE_REQUEST, IPCP_DATA_ENCODED, (void*)content, len);                      
            if (ecuaddress == NULL) {
                ALOGE("sendUrlInfoRequest ecuaddress is null\n");
                err = STACK_FAILURE_PARM_INVALID;
            } else if (strcmp(ecuaddress, DIAGNOSE_ADDR_ADCU) == 0) {
                ALOGD("sendUrlInfoRequest send ipcp to adcu\n");
                err = ipcp_send(peer_adcu_server, packet); 
            } else if (strcmp(ecuaddress, DIAGNOSE_ADDR_FLC) == 0) {
                ALOGD("sendUrlInfoRequest send ipcp to flc\n");
                err = ipcp_send(peer_flc_server, packet); 
            } else {

            }
                                 
            if (err != STACK_SEND_MSG_SUCCESS) {
                ALOGE("%s: ipcp_send err : %d", __FUNCTION__, err);
            } else {
                ALOGV("sendUrlInfoRequest ipcp send success");
            }
        } else {
            ALOGE("sendUrlInfoRequest encode failed\n");
            encodeBuffer.printErrorInfo();
        }

    };
    mThread.schedule(task, gDefaultDelay.common);
    std::this_thread::sleep_for(std::chrono::milliseconds(150));
}

void Ota::sendUrlInfoSync() {
    ALOGI("%s", __func__);
    sendUrlInfoRequest();

    while (mRetryCount < 2) {
        if (mIPCPResponseResult.has_value() && mIPCPResponseResult.value()) {
            ALOGD("sendUrlInfoSync ipcp send and receive success!!!");
            mRetryCount = 0;
            mIPCPResponseResult.reset();
            mStartDownloadResult = true;  
            //send dhu notification
            const char* ecuaddress = (char*)this->mRequest.ecuAddress.c_str();
            const char* isotimestamp = (char*)this->mRequest.isotimestamp.c_str();
            const char* installationorder = (char*)this->mRequest.installationOrderId.c_str();
            const char* newstatus = "DOWNLOAD-DISTRIBUTE-START";
            const char* reason = "DOWNLOAD-AGENT";
            sendDHUAssignmentNotification(ecuaddress, installationorder, isotimestamp, newstatus, reason);
            return;
        } else {
            if (mRetryCount < 2) {
                mRetryCount++;
                ALOGE("sendUrlInfoSync ipcp retry again!!!");
                //retry send url info
                sendUrlInfoRequest();
            } else {
                //retry failed
                mRetryCount = 0;
                mIPCPResponseResult.reset();
                mStartDownloadResult = false;
                ALOGE("sendUrlInfoSync ipcp retry 3 times and all failed!!!");
                return;
            }
        }
        std::this_thread::sleep_for(std::chrono::milliseconds(100));
    }
}

void Ota::sendSignatureCertificateRequest() {
    ALOGI("%s", __func__);
    //0B55
    auto task = [this]() {
        const char* content = NULL;
        char* tmpData = NULL;
        char* ecuaddress = (char*)this->mRequest.ecuAddress.c_str();
        int stat, len;
        bool trace = FALSE;

        ipcp_stack_err_t err = STACK_FAILURE_UNKOWN;
        ASN1PEREncodeBuffer encodeBuffer(false);
        ASN1T_New_OpOTASignatureCertificate_Request data;
        data.oTASignatureCertificate = (char*)this->mRequest.signatureCertificate.c_str();
        ALOGD("%s: data.oTASignatureCertificate  = %s ", __func__, data.oTASignatureCertificate);
        
        ASN1C_New_OpOTASignatureCertificate_Request opOTASignatureCertificate_Request(encodeBuffer, data);
        if ((stat = opOTASignatureCertificate_Request.Encode()) == 0) {
            if (trace) {
                ALOGV("sendSignatureCertificateRequest Encoding was successful\n");
                ALOGV("sendSignatureCertificateRequest Hex dump of encoded record:\n");
                encodeBuffer.hexDump();
                ALOGV("sendSignatureCertificateRequest Binary dump:\n");
                encodeBuffer.binDump("Data");
            }
            ALOGV("sendSignatureCertificateRequest encode success");
            len = encodeBuffer.getMsgLen();
            content = (char*)encodeBuffer.getMsgPtr();
            ipcp_packet_t* packet = build_ipcp_packet(SERVICE_ID, OP_ID_OTA_SIGNATURE_CERTIFICATE, OP_TYPE_REQUEST, IPCP_DATA_ENCODED, (void*)content, len);                      
            if (ecuaddress == NULL) {
                ALOGE("sendSignatureCertificateRequest ecuaddress is null\n");
                err = STACK_FAILURE_PARM_INVALID;
            } else if (strcmp(ecuaddress, DIAGNOSE_ADDR_ADCU) == 0) {
                ALOGD("sendSignatureCertificateRequest send ipcp to adcu\n");
                err = ipcp_send(peer_adcu_server, packet); 
            } else if (strcmp(ecuaddress, DIAGNOSE_ADDR_FLC) == 0) {
                ALOGD("sendSignatureCertificateRequest send ipcp to flc\n");
                err = ipcp_send(peer_flc_server, packet); 
            } else {

            }
                                 
            if (err != STACK_SEND_MSG_SUCCESS) {
                ALOGE("%s: ipcp_send err : %d", __FUNCTION__, err);
            } else {
                ALOGV("sendSignatureCertificateRequest ipcp send success");
            }
        } else {
            ALOGE("sendSignatureCertificateRequest encode failed\n");
            encodeBuffer.printErrorInfo();
        }

    };
    mThread.schedule(task, gDefaultDelay.common);
    std::this_thread::sleep_for(std::chrono::milliseconds(100));
}

void Ota::sendSignatureCertificateSync() {
    ALOGI("%s", __func__);
    //send ipcp signature certificate
    sendSignatureCertificateRequest();

    while (mRetryCount < 2) {
        if (mIPCPResponseResult.has_value()) {
            if (mIPCPResponseResult.value()) {
                ALOGD("sendSignatureCertificateSync ipcp send and receive success!!!");
                //send ipcp2
                mRetryCount = 0;
            mRetryCount = 0;
                mRetryCount = 0;
            mRetryCount = 0;
                mRetryCount = 0;
                sendUrlInfoSync();
                break;
            } else {
                mRetryCount = 0;
                mIPCPResponseResult.reset();
                mStartDownloadResult = false;
                ALOGE("sendSignatureCertificateSync ipcp receive nok!!!");
                break;
            }
        } else {
            if (mRetryCount < 2) {
                mRetryCount++;
                ALOGE("sendSignatureCertificateSync ipcp retry again!!!");
                //retry send signature certificate
                sendSignatureCertificateRequest();
            } else {
                //retry failed
                mRetryCount = 0;
                mIPCPResponseResult.reset();
                mStartDownloadResult = false;
                ALOGE("sendSignatureCertificateSync ipcp retry 3 times and all failed!!!");
                break;
            }
        }
        std::this_thread::sleep_for(std::chrono::milliseconds(100));
    }
}

void Ota::sendAssignmentFileInfoRequest() {
    ALOGI("%s", __func__);
    //0x0B29
    auto task = [this]() {
        const char* content = NULL;
        char* ecuaddress = (char*)mRequest.ecuAddress.c_str();
        const std::string validtime("41704532219831327688412");//size23
        int stat, len;
        bool trace = FALSE;

        ipcp_stack_err_t err = STACK_FAILURE_UNKOWN;
        ASN1PEREncodeBuffer encodeBuffer(false);
        ASN1T_New_OpOTASetAssignmentFileInfo_Request data;
        
        data.installationorder.uuid = (const char*)mRequest.installationOrderId.c_str();
        data.ecuremaining = 0;
        string2OCTET(ecuaddress, data.ecuaddress.addr.data);
        data.ecuaddress.addr.numocts = strlen(ecuaddress) / 2;
        data.lastsegment = (OSBOOL)true;
        ALOGD("%s: data.installationorder.uuid  = %s ", __func__, data.installationorder.uuid);
        ALOGD("%s: data.ecuaddress.addr.numocts = %d ", __func__, data.ecuaddress.addr.numocts);

        // assignfileinfo
        if (mRequest.softwareInstallationInstructions.size() > 0) {
            ASN1C__SetOfNew_AssignmentFileInfo assignmentFileInfoList(
                        data.assignfileinfo);
            
            for (size_t i = 0; i < mRequest.softwareInstallationInstructions.size(); i++) {
                SoftwareInstallationInstructionHal softwareInstallationInstructionHal = this->mRequest.softwareInstallationInstructions[i];
                ASN1T_New_AssignmentFileInfo* assignmentFileInfo = assignmentFileInfoList.AppendNewElement();
                assignmentFileInfo->m.flashgroupidPresent = 1;
                assignmentFileInfo->m.downloadtypePresent = 1;
                assignmentFileInfo->m.installationtypePresent = 1;
                assignmentFileInfo->m.fileencryptiontypePresent = 1;
                assignmentFileInfo->m.validtimePresent = 0;
                assignmentFileInfo->m.validdatePresent = 0;

                assignmentFileInfo->filename.name = (OSUTF8CHAR*)softwareInstallationInstructionHal.fileName.c_str();
                assignmentFileInfo->flashgroupid = (OSUINT32)softwareInstallationInstructionHal.flashGroupId;

                // ADCU 那边不关心这个字段
                // string2OCTET((char*)mRequest.downloadType.c_str(), assignmentFileInfo->downloadtype.data);
                // assignmentFileInfo->downloadtype.numocts = strlen((char*)mRequest.downloadType.c_str()) / 2;
                assignmentFileInfo->downloadtype.data[0] = 0x01;
                assignmentFileInfo->downloadtype.numocts = 1;

                // ADCU 那边不关心这个字段
                // string2OCTET((char*)mRequest.installationType.c_str(), assignmentFileInfo->installationtype.data);
                // assignmentFileInfo->installationtype.numocts = strlen((char*)mRequest.installationType.c_str()) / 2;
                assignmentFileInfo->installationtype.data[0] = 0x01;
                assignmentFileInfo->installationtype.numocts = 1;

                string2OCTET((char*)softwareInstallationInstructionHal.encryptionInfo.c_str(), assignmentFileInfo->fileencryptiontype.data);
                assignmentFileInfo->fileencryptiontype.numocts = strlen((char*)softwareInstallationInstructionHal.encryptionInfo.c_str()) / 2;

                string2OCTET((char*)softwareInstallationInstructionHal.fileSignature.c_str(), assignmentFileInfo->softwarepartsignature.softwarepartsignature1.data);
                assignmentFileInfo->softwarepartsignature.softwarepartsignature1.numocts = strlen((char*)softwareInstallationInstructionHal.fileSignature.c_str()) / 2;

                string2OCTET((char*)softwareInstallationInstructionHal.fileChecksum.c_str(), assignmentFileInfo->filechecksum.data);
                assignmentFileInfo->filechecksum.numocts = strlen((char*)softwareInstallationInstructionHal.fileChecksum.c_str()) / 2;

                assignmentFileInfo->validtime = (const char*)validtime.c_str();

                // ALOGD("%s: i = %zu  filename.name = %s ", __func__, i,  assignmentFileInfo->filename.name);
                // ALOGD("%s: i = %zu  downloadtype = %s ", __func__, i,  assignmentFileInfo->downloadtype.data);
                // ALOGD("%s: i = %zu  installationtype = %s ", __func__, i,  assignmentFileInfo->installationtype.data);
            }
        }
        
        ASN1C_New_OpOTASetAssignmentFileInfo_Request opOTASetAssignmentFileInfo_Request(encodeBuffer, data);
        if ((stat = opOTASetAssignmentFileInfo_Request.Encode()) == 0) {
            if (trace) {
                ALOGV("sendAssignmentFileInfoRequest Encoding was successful\n");
                ALOGV("sendAssignmentFileInfoRequest Hex dump of encoded record:\n");
                encodeBuffer.hexDump();
                ALOGV("sendAssignmentFileInfoRequest Binary dump:\n");
                encodeBuffer.binDump("Data");
            }
            ALOGV("sendAssignmentFileInfoRequest encode success");
            len = encodeBuffer.getMsgLen();
            content = (char*)encodeBuffer.getMsgPtr();
            ipcp_packet_t* packet = build_ipcp_packet(SERVICE_ID, OP_ID_OTA_SET_ASSIGNMENT_FILE_INFO, OP_TYPE_REQUEST, IPCP_DATA_ENCODED, (void*)content, len);                      
            if (ecuaddress == NULL) {
                ALOGE("sendAssignmentFileInfoRequest ecuaddress is null\n");
                err = STACK_FAILURE_PARM_INVALID;
            } else if (strcmp(ecuaddress, DIAGNOSE_ADDR_ADCU) == 0) {
                ALOGD("sendAssignmentFileInfoRequest send ipcp to adcu\n");
                err = ipcp_send(peer_adcu_server, packet); 
            } else if (strcmp(ecuaddress, DIAGNOSE_ADDR_FLC) == 0) {
                ALOGD("sendAssignmentFileInfoRequest send ipcp to flc\n");
                err = ipcp_send(peer_flc_server, packet); 
            } else {

            }
                                 
            if (err != STACK_SEND_MSG_SUCCESS) {
                ALOGE("%s: ipcp_send err : %d", __FUNCTION__, err);
            } else {
                ALOGV("sendAssignmentFileInfoRequest ipcp send success");
            }
        } else {
            ALOGE("sendAssignmentFileInfoRequest encode failed\n");
            encodeBuffer.printErrorInfo();
        }

    };
    mThread.schedule(task, gDefaultDelay.common);
    std::this_thread::sleep_for(std::chrono::milliseconds(100));
}

void Ota::sendAssignmentFileInfoSync() {
    ALOGI("%s", __func__);
    //send ipcp assignment file info
    sendAssignmentFileInfoRequest();

    while (mRetryCount < 2) {
        if (mIPCPResponseResult.has_value() && mIPCPResponseResult.value()) {
            ALOGD("sendAssignmentFileInfoSync ipcp send and receive success!!!");
            //send ipcp signature certificate
            mRetryCount = 0;
            sendSignatureCertificateSync();
            return;
        } else {
            if (mRetryCount < 2) {
                mRetryCount++;
                ALOGE("sendAssignmentFileInfoSync ipcp retry again!!!");
                //retry send assignment file info
                sendAssignmentFileInfoRequest();
            } else {
                //retry failed
                mRetryCount = 0;
                mIPCPResponseResult.reset();
                mStartDownloadResult = false;
                ALOGE("sendAssignmentFileInfoSync ipcp retry 3 times and all failed!!!");
                return;
            }
        }
        std::this_thread::sleep_for(std::chrono::milliseconds(100));
    }
}

void Ota::sendWriteInstallInstructionRequest() {
    ALOGI("%s", __func__);
    //0x0B16
    auto task = [this]() {
        const char* content = NULL;
        //char* tmpData = NULL;
        char* ecuaddress = (char*)this->mRequest.ecuAddress.c_str();
        const std::string validtime("41704532219831327688412");//size23
        int stat, len;
        bool trace = FALSE;
        
        ipcp_stack_err_t err = STACK_FAILURE_UNKOWN;

        ASN1PEREncodeBuffer encodeBuffer(false);
        ASN1T_New_OpOTAWriteInstallationInstructions_Request data;

        data.installationorder.uuid = (const char*)this->mRequest.installationOrderId.c_str();
        data.ecuremaining = 0;

        ALOGD("%s:  uuid = %s ", __func__,  data.installationorder.uuid);

        // installationinstruction
        data.installationinstruction.m.operationsequencePresent = 1;

        data.installationinstruction.installationinstructionsversion = "000001";//size6
        data.installationinstruction.bssid = (OSUTF8CHAR*)this->mRequest.bssId.c_str();
        data.installationinstruction.displayedversion = (OSUTF8CHAR*)this->mRequest.displayedVersion.c_str();
        data.installationinstruction.targetECUNum = (OSUINT8)mRequest.targetECUNum;
        data.installationinstruction.maximumParallelECUNum = (OSUINT8)mRequest.maximumParallelNum;
        data.installationinstruction.requiredpreparationtime = (OSUINT32)mRequest.requiredPreparationTime;
        data.installationinstruction.expectedinstallationtime = (OSUINT32)mRequest.expectedInstallationTime;
        string2OCTET((char*)this->mRequest.securityCode.c_str(), data.installationinstruction.area1112securitycode.securitykey.data);
        data.installationinstruction.area1112securitycode.securitykey.numocts = strlen((char*)this->mRequest.securityCode.c_str()) / 2;
        data.installationinstruction.operationsequence = this->mRequest.operationSequence;

        ALOGD("%s:  installationinstructionsversion = %s ", __func__,  data.installationinstruction.installationinstructionsversion);
        ALOGD("%s:  bssid = %s ", __func__,  data.installationinstruction.bssid);
        ALOGD("%s:  displayedversion = %s ", __func__,  data.installationinstruction.displayedversion);
        ALOGD("%s:  data.installationinstruction.area1112securitycode.securitykey.data = %s ", __func__, (char*)this->mRequest.securityCode.c_str());

        // ecuinstructions
        data.installationinstruction.ecuinstructions.m.sblnotpresentPresent = 1;

        string2OCTET(ecuaddress, data.installationinstruction.ecuinstructions.ecuaddress.addr.data);
        data.installationinstruction.ecuinstructions.ecuaddress.addr.numocts = strlen(ecuaddress) / 2;
        data.installationinstruction.ecuinstructions.queuedrequest = (OSUINT16)mRequest.queuedRequest;
        string2OCTET((char*)this->mRequest.securityKey.c_str(), data.installationinstruction.ecuinstructions.securitycode.securitykey.data);
        data.installationinstruction.ecuinstructions.securitycode.securitykey.numocts = strlen((char*)this->mRequest.securityKey.c_str()) / 2;
        data.installationinstruction.ecuinstructions.sblnotpresent = this->mRequest.sblNotPresent;

        ALOGD("%s:  data.installationinstruction.ecuinstructions.securitycode.securitykey.data = %s ", __func__, (char*)this->mRequest.securityKey.c_str());
        ALOGD("%s:  sblnotpresent = %d ", __func__,  data.installationinstruction.ecuinstructions.sblnotpresent);

        // softwarepartinstallationinstruction
        if (this->mRequest.softwareInstallationInstructions.size() > 0) {
            ASN1C_New_Ecuinstructionsdata_softwarepartinstallationinstruction softwarepartinstallationinstructionList(
                        data.installationinstruction.ecuinstructions.softwarepartinstallationinstruction);
            
            for (size_t i = 0; i < this->mRequest.softwareInstallationInstructions.size(); i++) {
                ASN1T_New_SoftwarePartInstallationInstruction* softwarepartinstallationinstruction = 
                softwarepartinstallationinstructionList.AppendNewElement();

                softwarepartinstallationinstruction->m.flashgroupidPresent = 1;
                softwarepartinstallationinstruction->m.downloadtypePresent = 1;
                softwarepartinstallationinstruction->m.installationtypePresent = 1;
                softwarepartinstallationinstruction->m.fileencryptiontypePresent = 1;
                softwarepartinstallationinstruction->m.validtimePresent = 0;
                softwarepartinstallationinstruction->m.validdatePresent = 0;

                softwarepartinstallationinstruction->filename.name = (OSUTF8CHAR*)mRequest.softwareInstallationInstructions[i].fileName.c_str();//(OSUTF8CHAR*)opOTAWriteInstallationInstructionHal.dataList[i].filename.c_str();
                softwarepartinstallationinstruction->flashgroupid = (OSUINT32) mRequest.flashGroupId;
                softwarepartinstallationinstruction->downloadtype = (const char*)mRequest.downloadType.c_str();
                softwarepartinstallationinstruction->installationtype = (const char*)mRequest.installationType.c_str();
                softwarepartinstallationinstruction->fileencryptiontype = (const char*)mRequest.softwareInstallationInstructions[i].encryptionType.c_str();
                softwarepartinstallationinstruction->estimatedinstallationtime = mRequest.softwareInstallationInstructions[i].estimatedInstallationTime;
                
                ALOGD("%s: i = %zu  filename.name = %s ", __func__, i,  softwarepartinstallationinstruction->filename.name);
                ALOGD("%s: i = %zu  downloadtype = %s ", __func__, i,  softwarepartinstallationinstruction->downloadtype);
                ALOGD("%s: i = %zu  installationtype = %s ", __func__, i,  softwarepartinstallationinstruction->installationtype);
                ALOGD("%s: i = %zu  fileencryptiontype = %s ", __func__, i,  softwarepartinstallationinstruction->fileencryptiontype);
                ALOGD("%s: i = %zu  estimatedinstallationtime = %d ", __func__, i,  softwarepartinstallationinstruction->estimatedinstallationtime);
                ALOGD("%s: i = %zu  flashgroupid = %d ", __func__, i,  softwarepartinstallationinstruction->flashgroupid);
            }
        }

        // assignmentvalidationpre
        data.installationinstruction.assignmentvalidationpre.clientversion.uuid = (const char*)this->mRequest.clientVersion.c_str();

        // assignmentvalidationpost
        string2OCTET(ecuaddress, data.installationinstruction.assignmentvalidationpost.ecuaddress.addr.data);
        data.installationinstruction.assignmentvalidationpost.ecuaddress.addr.numocts = strlen(ecuaddress) / 2;

        // ecudata 加入会导致encode时softwarepartinstallationinstruction为空 目前ecudata数据也不使用
        // if (this->mRequest.validationKeys.size() > 0) {
        //     ASN1C_New_POSTvalidation_ecudata ecudataList(
        //                 data.installationinstruction.assignmentvalidationpost.ecudata);
        //     for (size_t i = 0; i < this->mRequest.validationKeys.size(); i++) {
        //         ValidatioKeyHal validatioKeyHal = this->mRequest.validationKeys[i];
        //         ASN1T_New_ECUdata* ecuData = ecudataList.AppendNewElement();

        //         ALOGD("%s: i = %zu  valkey = %s ", __func__, i,  (char*)validatioKeyHal.didName.c_str());
        //         string2OCTET((char*)validatioKeyHal.didName.c_str(), ecuData->keyname.valkey.data);
        //         ecuData->keyname.valkey.numocts = strlen((char*)validatioKeyHal.didName.c_str()) / 2;

        //         ALOGD("%s: i = %zu  didValue = %s ", __func__, i,  (char*)validatioKeyHal.didValue.c_str());
        //         string2OCTET((char*)validatioKeyHal.didValue.c_str(), ecuData->keyvalue.data);
        //         ecuData->keyvalue.numocts = strlen((char*)validatioKeyHal.didValue.c_str()) / 2;
        //     }
        // }

        ASN1C_New_OpOTAWriteInstallationInstructions_Request opOTAWriteInstallationInstructions_Request(encodeBuffer, data);
        ALOGD("%s: reach here3", __func__);
        if ((stat = opOTAWriteInstallationInstructions_Request.Encode()) == 0) {
            if (trace) {
                ALOGV("sendWriteInstallInstructionRequest Encoding was successful\n");
                ALOGV("sendWriteInstallInstructionRequest Hex dump of encoded record:\n");
                encodeBuffer.hexDump();
                ALOGV("sendWriteInstallInstructionRequest Binary dump:\n");
                encodeBuffer.binDump("Data");
            }
            ALOGV("sendWriteInstallInstructionRequest encode success");
            len = encodeBuffer.getMsgLen();
            content = (char*)encodeBuffer.getMsgPtr();
            ipcp_packet_t* packet = build_ipcp_packet(SERVICE_ID, OP_ID_OTA_WRITE_INSTALLATION_INSTRUCTION, OP_TYPE_REQUEST, IPCP_DATA_ENCODED, (void*)content, len);                      
            if (ecuaddress == NULL) {
                ALOGE("sendWriteInstallInstructionRequest ecuaddress is null\n");
                err = STACK_FAILURE_PARM_INVALID;
            } else if (strcmp(ecuaddress, DIAGNOSE_ADDR_ADCU) == 0) {
                ALOGD("sendWriteInstallInstructionRequest send ipcp to adcu\n");
                err = ipcp_send(peer_adcu_server, packet); 
            } else if (strcmp(ecuaddress, DIAGNOSE_ADDR_FLC) == 0) {
                ALOGD("sendWriteInstallInstructionRequest send ipcp to flc\n");
                err = ipcp_send(peer_flc_server, packet); 
            } else {

            }
                                 
            if (err != STACK_SEND_MSG_SUCCESS) {
                ALOGE("%s: ipcp_send err : %d", __FUNCTION__, err);
            } else {
                ALOGV("sendWriteInstallInstructionRequest ipcp send success");
            }
        } else {
            ALOGE("sendWriteInstallInstructionRequest encode failed\n");
            encodeBuffer.printErrorInfo();
        }
    };
    mThread.schedule(task, gDefaultDelay.common);
    std::this_thread::sleep_for(std::chrono::milliseconds(100));
}

void Ota::sendWriteInstallInstructionSync() {
    ALOGI("%s", __func__);
    //send ipcp write install instruction
    sendWriteInstallInstructionRequest();

    while (true) {
        if (mIPCPResponseResult.has_value() && mIPCPResponseResult.value()) {
            ALOGD("sendWriteInstallInstructionSync ipcp send and receive success!!!");
            //send ipcp assignmentFileInfoSync
            mRetryCount = 0;
            mIPCPResponseResult.reset();
            sendAssignmentFileInfoSync();
            return;
        } else {
            if (mRetryCount < 2) {
                mRetryCount++;
                ALOGE("sendWriteInstallInstructionSync ipcp retry again!!!");
                //retry send write install instruction
                sendWriteInstallInstructionRequest();
            } else {
                //retry failed
                mRetryCount = 0;
                mIPCPResponseResult.reset();
                mStartDownloadResult = false;
                ALOGE("sendWriteInstallInstructionSync ipcp retry 3 times and all failed!!!");
                return;
            }
        }
        std::this_thread::sleep_for(std::chrono::milliseconds(100));
    }
}

Return<StatusCode> Ota::startDistributeEcuDownload(const StartDownloadRequestHal& request) {
    ALOGI("%s", __func__);
    mStartDownloadResult.reset();
    mIPCPResponseResult.reset();
    mRetryCount = 0;
    mStartTime = std::chrono::steady_clock::now();
    mRequest = request;

    sendWriteInstallInstructionSync();
    
    while (!mStartDownloadResult.has_value()) {
        std::this_thread::sleep_for(std::chrono::milliseconds(100));
        auto now = std::chrono::steady_clock::now();
        auto elapsed = std::chrono::duration_cast<std::chrono::seconds>(now - mStartTime);
        if (elapsed.count() >= 10) {
            ALOGE("startDistributeEcuDownload timeout!!!");
            return StatusCode::FAILED;
        }
    }
    if (mStartDownloadResult.value()) {
        ALOGE("startDistributeEcuDownload success!!!");
        return StatusCode::SUCCESS;
    } else {
        ALOGE("startDistributeEcuDownload failed!!!");
        return StatusCode::FAILED;
    }
}

Return<StatusCode> Ota::pauseDistributeEcuDownload(const OpOTAECUAssignmentStatusHal& opOTAECUAssignmentStatusHal) {
    ALOGI("%s", __func__);
    const char* uuid = (const char*)opOTAECUAssignmentStatusHal.installationorder.c_str();
    const char* timestamp = (const char*)opOTAECUAssignmentStatusHal.isotimestamp.c_str();
    const char* newstatus = (const char*)opOTAECUAssignmentStatusHal.newstatus.c_str();
    const char* reason = (const char*)opOTAECUAssignmentStatusHal.reason.c_str();
    const char* ecuaddress = (const char*)opOTAECUAssignmentStatusHal.ecuaddress.c_str();

    ALOGD("pauseDistributeEcuDownload uuid = %s", uuid);
    ALOGD("pauseDistributeEcuDownload timestamp = %s", timestamp);
    ALOGD("pauseDistributeEcuDownload newstatus = %s", newstatus);
    ALOGD("pauseDistributeEcuDownload reason = %s", reason);
    ALOGD("pauseDistributeEcuDownload ecuaddress = %s", ecuaddress);
    sendDHUAssignmentNotification(ecuaddress, uuid, timestamp, newstatus, reason);
    
    return StatusCode::SUCCESS;
}

Return<StatusCode> Ota::resumeDistributeEcuDownload(const OpOTAECUAssignmentStatusHal& opOTAECUAssignmentStatusHal) {
    ALOGI("%s", __func__);
    const char* uuid = (const char*)opOTAECUAssignmentStatusHal.installationorder.c_str();
    const char* timestamp = (const char*)opOTAECUAssignmentStatusHal.isotimestamp.c_str();
    const char* newstatus = (const char*)opOTAECUAssignmentStatusHal.newstatus.c_str();
    const char* reason = (const char*)opOTAECUAssignmentStatusHal.reason.c_str();
    const char* ecuaddress = (const char*)opOTAECUAssignmentStatusHal.ecuaddress.c_str();

    ALOGD("resumeDistributeEcuDownload uuid = %s", uuid);
    ALOGD("resumeDistributeEcuDownload timestamp = %s", timestamp);
    ALOGD("resumeDistributeEcuDownload newstatus = %s", newstatus);
    ALOGD("resumeDistributeEcuDownload reason = %s", reason);
    ALOGD("resumeDistributeEcuDownload ecuaddress = %s", ecuaddress);
    sendDHUAssignmentNotification(ecuaddress, uuid, timestamp, newstatus, reason);
    return StatusCode::SUCCESS;
}

Return<StatusCode> Ota::terminateDistributeEcuDownload(const OpOTAECUAssignmentStatusHal& opOTAECUAssignmentStatusHal) {
    ALOGI("%s", __func__);
    const char* uuid = (const char*)opOTAECUAssignmentStatusHal.installationorder.c_str();
    const char* timestamp = (const char*)opOTAECUAssignmentStatusHal.isotimestamp.c_str();
    const char* newstatus = (const char*)opOTAECUAssignmentStatusHal.newstatus.c_str();
    const char* reason = (const char*)opOTAECUAssignmentStatusHal.reason.c_str();
    const char* ecuaddress = (const char*)opOTAECUAssignmentStatusHal.ecuaddress.c_str();

    ALOGD("terminateDistributeEcuDownload uuid = %s", uuid);
    ALOGD("terminateDistributeEcuDownload timestamp = %s", timestamp);
    ALOGD("terminateDistributeEcuDownload newstatus = %s", newstatus);
    ALOGD("terminateDistributeEcuDownload reason = %s", reason);
    ALOGD("terminateDistributeEcuDownload ecuaddress = %s", ecuaddress);
    sendDHUAssignmentNotification(ecuaddress, uuid, timestamp, newstatus, reason);
    return StatusCode::SUCCESS;
}

Return<StatusCode> Ota::notificationToMasterChangeRsp(const hidl_string& status) {
    ALOGI("%s", __func__);

    auto task = [status]() {
        const char* content = NULL;
        int stat, len;
        bool trace = FALSE;
        ipcp_stack_err_t err;
        ASN1PEREncodeBuffer encodeBuffer(false);
        ASN1T_OpOTANotificationToMaster_Response data;
        data.status = (const char*)status.c_str();
        ALOGD("notificationToMasterChangeRsp data.status = %s", data.status);
        ASN1C_OpOTANotificationToMaster_Response OpOTANotificationToMaster_ResponsePDU(encodeBuffer, data);
        if ((stat = OpOTANotificationToMaster_ResponsePDU.Encode()) == 0) {
            if (trace) {
                ALOGV("Encoding was successful\n");
                encodeBuffer.hexDump();
                encodeBuffer.binDump("Data");
            }
            len = encodeBuffer.getMsgLen();
            content = (char*)encodeBuffer.getMsgPtr();
            ipcp_packet_t *packet = build_ipcp_packet(SERVICE_ID, OP_ID_OTA_NOTIFICATION_TO_MASTER_CHANGE,
                                                      OP_TYPE_RESPONSE, IPCP_DATA_ENCODED,(void *)content, len);

            if ((err = ipcp_send(peer_ota_server, packet)) != STACK_SEND_MSG_SUCCESS) {
                ALOGE("%s: ipcp_send err : %d", __FUNCTION__, err);
            } else {
                ALOGV("notificationToMasterChangeRsp ipcp send success");
            }

        } else {
            ALOGE("notificationToMasterChangeRsp OpOTANotificationToMaster_ResponsePDU encode failed\n");
            encodeBuffer.printErrorInfo();
        }
    };
    mThread.schedule(task, gDefaultDelay.common);
    return StatusCode::SUCCESS;
}

Return<StatusCode> Ota::scheduleTime(const hidl_string& installationOrder,
                                     InstallationConsent installationConsent,
                                     int32_t deltatime) {
    ALOGI("%s", __func__);

    StatusCode code = StatusCode::FAILED;


    auto task = [installationOrder, installationConsent, deltatime, &code]() {

        const char* uuid = (const char*)installationOrder.c_str();
        const char* content = NULL;
        int state, len;
        bool trace = FALSE;
        ipcp_stack_err_t err = STACK_FAILURE_UNKOWN;

        ASN1PEREncodeBuffer encodeBuffer(false);
        ASN1T_OpSetScheduleTime_Notification data;
        data.installationorder.uuid = uuid;
        int type = static_cast<int>(installationConsent);
        data.installationconsent = New_Installationconsent::Root(type);
        if (installationConsent == InstallationConsent::Schedule) {
            data.m.deltatimePresent = 1;
            data.deltatime = (OSUINT32)deltatime;
        } else {
            data.m.deltatimePresent = 0;
        }
        ALOGD("scheduleTime data.installationorder.uuid = %s",
              data.installationorder.uuid);
        ALOGD("scheduleTime data.installationconsent = %d", data.installationconsent);
        ALOGD("scheduleTime data.deltatime = %d", data.deltatime);

        ASN1C_OpSetScheduleTime_Notification OpSetScheduleTime_Notification(encodeBuffer, data);
        if ((state = OpSetScheduleTime_Notification.Encode()) == 0) {
            if (trace) {
                ALOGV("scheduleTime Encoding was successful\n");
                ALOGV("scheduleTime Hex dump of encoded record:\n");
                encodeBuffer.hexDump();
                ALOGV("scheduleTime Binary dump:\n");
                encodeBuffer.binDump("Data");
            }
            ALOGD("OpSetScheduleTime_Notification encode success");
            len = encodeBuffer.getMsgLen();
            content = (char*) encodeBuffer.getMsgPtr();
            ipcp_packet_t *packet = build_ipcp_packet(SERVICE_ID, OP_ID_OTA_SET_SCHEDULE_TIME, OP_TYPE_NOTIFICATION,
                                                      IPCP_DATA_ENCODED, (void*)content, len);
            if ((err = ipcp_send(peer_ota_server, packet)) != STACK_SEND_MSG_SUCCESS) {
                code = StatusCode::FAILED;
                ALOGE("%s: ipcp_send err : %d", __FUNCTION__, err);
            } else {
                code = StatusCode::SUCCESS;
                ALOGV("scheduleTime ipcp send success");
            }
        } else {
            code = StatusCode::FAILED;
            ALOGE("%s: encode failed", __FUNCTION__);
        }
    };

    std::packaged_task<void()> tsk(task);
    std::future<void> ret = tsk.get_future();
    mThread.schedule([&tsk]() { tsk(); }, gDefaultDelay.common);
    ALOGV("scheduleTime wait for function exec");
    ret.get();
    ALOGV("scheduleTime get result code:%d", code);
    return code;
}

Return<int32_t> Ota::requestSchInstallTime(int32_t timeout) {
    ALOGI("%s", __func__);

    auto task = []() {
        const char* content = NULL;
        int stat, len;
        bool trace = FALSE;
        ipcp_stack_err_t err;
        ASN1PEREncodeBuffer encodeBuffer(false);
        ASN1C_OpGeneric_Request OpGeneric_RequestPDU(encodeBuffer);
        if ((stat = OpGeneric_RequestPDU.Encode()) == 0) {
            if (trace) {
                ALOGV("Encoding was successful\n");
                encodeBuffer.hexDump();
                encodeBuffer.binDump("Data");
            }
            len = encodeBuffer.getMsgLen();
            content = (char*)encodeBuffer.getMsgPtr();
            ipcp_packet_t *packet = build_ipcp_packet(SERVICE_ID, OP_ID_SYNC_SCH_INSTALL_TIME,
                                                      OP_TYPE_REQUEST, IPCP_DATA_ENCODED,(void *)content, len);

            if ((err = ipcp_send(peer_ota_server, packet)) != STACK_SEND_MSG_SUCCESS) {
                ALOGE("%s: ipcp_send err : %d", __FUNCTION__, err);
            } else {
                ALOGV("requestSchInstallTime ipcp send success");
            }

        } else {
            ALOGE("requestSchInstallTime OpGeneric_RequestPDU encode failed\n");
            encodeBuffer.printErrorInfo();
        }
    };
    std::unique_lock<std::mutex> lock(mMutex);
    mDeltaTime = -1;
    mThread.schedule(task, gDefaultDelay.common);
    // 等待tcam返回OP_ID_SYNC_SCH_INSTALL_TIME
    mCv.wait_for(lock, std::chrono::milliseconds(timeout), []{ return mDeltaTime != -1; });
    return mDeltaTime;
}

Return<StatusCode> Ota::setTcamSalesMode(SaleMode type, int32_t timeout) {
    ALOGI("%s", __func__);

    auto task = [type]() {
        const char* content = NULL;
        int stat, len;
        bool trace = FALSE;
        ipcp_stack_err_t err;
        ASN1PEREncodeBuffer encodeBuffer(false);
        ASN1T_OpOTAPreSaleInfo_Request data;
        data.preSale = (OSBOOL)(type == SaleMode::PreSale);
        ASN1C_OpOTAPreSaleInfo_Request OpOTAPreSaleInfo_Request(encodeBuffer, data);
        if ((stat = OpOTAPreSaleInfo_Request.Encode()) == 0) {
            if (trace) {
                ALOGV("Encoding was successful\n");
                encodeBuffer.hexDump();
                encodeBuffer.binDump("Data");
            }
            len = encodeBuffer.getMsgLen();
            content = (char*)encodeBuffer.getMsgPtr();
            ipcp_packet_t *packet = build_ipcp_packet(SERVICE_ID, OP_ID_PRE_SALE_INFO,
                                                      OP_TYPE_REQUEST, IPCP_DATA_ENCODED,(void *)content, len);

            if ((err = ipcp_send(peer_ota_server, packet)) != STACK_SEND_MSG_SUCCESS) {
                ALOGE("%s: ipcp_send err : %d", __FUNCTION__, err);
            } else {
                ALOGV("setTcamSalesMode ipcp send success");
            }

        } else {
            ALOGE("setTcamSalesMode OpOTAPreSaleInfo_Request encode failed\n");
            encodeBuffer.printErrorInfo();
        }
    };
    std::unique_lock<std::mutex> lock(mMutex);
    mPreSaleStatus = -1;
    mThread.schedule(task, gDefaultDelay.common);
    // 等待tcam返回OP_ID_PRE_SALE_INFO
    mCv.wait_for(lock, std::chrono::milliseconds(timeout), [] { return mPreSaleStatus != -1; });
    if (mPreSaleStatus == -1) {
        ALOGE("setTcamSalesMode timeout");
        mPreSaleStatus = (int32_t) StatusCode::FAILED;
    }
    return ((StatusCode) mPreSaleStatus);
}

//----------------------------------------------------------------
//------------------------ OTA TEST START ------------------------
ota_callback Ota::gOtaCallback = NULL;

Return<StatusCode> Ota::init_ota_ipcp_test() {
    ALOGD("%s", __func__);

    ipcp_transport_conf_t client_config;
    ipcp_stack_err_t error_code;

    init_ota_side_test(&client_config);
    error_code = ipcp_setup_with_opids(client_config, &ota_callbacks, Connectivity_OperationIDs, (sizeof(Connectivity_OperationIDs) / sizeof(Connectivity_OperationIDs[0])));

    if (error_code != 0) {
        ALOGE("ota client side setup error: %d", error_code);
        return StatusCode::FAILED;
    } else {
        ALOGV("ota client side setup success");
        return StatusCode::SUCCESS;
    }
}

void Ota::handleHidlDeath() {
    ALOGD("%s", __func__);
    sp<Ota> ota = Ota::getOta(cookie);
    sp<IOtaClientCallback> callback = ota->getCallback();
    unsubscribe(callback);
    ipcp_cleanup();
    // setupDtcnl();
}
//------------------------- OTA TEST END -------------------------
//----------------------------------------------------------------

Return<void> Ota::debug(const android::hardware::hidl_handle& handle, const android::hardware::hidl_vec<hidl_string>& options) {

    int fd = handle->data[0];
    ALOGE("%s", __func__);

    dprintf(fd, "ota-hal debug\n");

    dprintf(fd, "scheduleTime ret:%d\n", scheduleTime("123456789012345678901234567890123456", InstallationConsent::Schedule, 10000) == StatusCode::FAILED);
    return Void();
}

}  // namespace V2_0
}  // namespace ota
}  // namespace xma
}  // namespace ecarx
}  // namespace vendor
